/*
 * AVFrameQueue.h
 *
 *  Created on: 2015年6月9日
 *      Author: chuanjiang.zh@qq.com
 */

#ifndef AVFRAMEQUEUE_H_
#define AVFRAMEQUEUE_H_

#include "Ffmpeg.h"
#include "TCriticalSection.h"
#include <deque>

class AVFrameQueue
{
public:
    AVFrameQueue()
    {

    }

    ~AVFrameQueue()
    {
        clear();
    }

    size_t push(AVFrame* pFrame)
    {
        comn::AutoCritSec lock(m_cs);
        m_frames.push_back(pFrame);
        return m_frames.size();
    }

    AVFrame* pop()
    {
        comn::AutoCritSec lock(m_cs);
        AVFrame* frame = NULL;
        if (!m_frames.empty())
        {
            frame = m_frames.front();
            m_frames.pop_front();
        }
        return frame;
    }

    size_t size()
    {
        comn::AutoCritSec lock(m_cs);
        return m_frames.size();
    }

    void clear()
    {
        comn::AutoCritSec lock(m_cs);
        while (!m_frames.empty())
        {
            AVFrame* frame = m_frames.front();
            m_frames.pop_front();
            av_frame_free(&frame);
        }
    }

    size_t popUntil(int64_t pts)
    {
    	size_t count = 0;
    	comn::AutoCritSec lock(m_cs);
		while (!m_frames.empty())
		{
			AVFrame* frame = m_frames.front();
			int64_t framePts = (frame->pts == AV_NOPTS_VALUE) ? frame->pkt_pts : frame->pts;
			if (framePts <= pts)
			{
				m_frames.pop_front();
				av_frame_free(&frame);
				count ++;
			}
			else
			{
				break;
			}
		}
		return count;
    }

    AVFrame* pop(size_t& queSize)
    {
        comn::AutoCritSec lock(m_cs);
        AVFrame* frame = NULL;
        if (!m_frames.empty())
        {
            frame = m_frames.front();
            m_frames.pop_front();

            queSize = m_frames.size();
        }
        return frame;
    }

    size_t popUntilSize(size_t size)
    {
        size_t count = 0;
        comn::AutoCritSec lock(m_cs);
        while (m_frames.size() > size)
        {
            AVFrame* frame = m_frames.front();
            m_frames.pop_front();
            av_frame_free(&frame);
            count ++;
        }
        return count;
    }

	int64_t getDuration()
	{
		int64_t duration = 0;
		comn::AutoCritSec lock(m_cs);
		if (m_frames.size() > 1)
		{
			AVFrame* frame = m_frames.front();
			if (frame->nb_samples > 0)
			{
				duration = (int64_t)(frame->nb_samples) * m_frames.size() * 1000000 / frame->sample_rate;
			}
			else
			{
				duration = m_frames.front()->pts - m_frames.back()->pts;
			}
		}
		return duration;
	}

protected:
    typedef std::deque< AVFrame* >  FrameDeque;

    FrameDeque  m_frames;
    comn::CriticalSection   m_cs;

};



#endif /* AVFRAMEQUEUE_H_ */
